package main

import (
	"context"          // 用于gRPC请求的上下文控制（超时、取消）
	"log"              // 标准库日志，用于打印测试过程的信息和错误
	"time"             // 用于设置上下文超时时间

	"gameServer/config" // 配置包，用于从JSON文件加载gRPC服务端地址
	"gameServer/proto"  // Protobuf编译后的包，包含gRPC客户端 stub 和请求/响应结构体

	"google.golang.org/grpc"                  // gRPC核心库，提供客户端连接能力
	"google.golang.org/grpc/credentials/insecure" // 提供"不安全"的传输凭证（测试环境用，不加密）
)

/*
gRPC客户端测试程序：
专门用于测试游戏服务器的gRPC会话服务接口，覆盖"创建会话→添加玩家→验证状态→启动会话→结束会话→清理会话"的完整流程，
确保服务端的会话管理功能正常工作。测试结果通过日志输出，便于快速定位接口调用问题。
*/

func main() {
	// -------------------------- 第一步：加载配置，获取gRPC服务端地址 --------------------------
	// 创建文件配置对象，指定配置文件绝对路径（存储gRPC服务端地址等参数）
	// 作用：从本地JSON文件读取服务端地址，避免硬编码（如服务端地址变更时只需改配置）
	cfg := config.NewFileConfig("d:\\vscode_\\myFile\\GOLANG\\game_server\\config\\config.json")
	// 加载配置文件：解析JSON内容到cfg对象，加载失败则打印致命错误并退出测试
	if err := cfg.Load(); err != nil {
		log.Fatalf("Failed to load config: %v", err) // Fatalf终止程序，配置加载失败无法继续测试
	}

	// 从配置中读取gRPC服务端地址（配置文件中对应"grpc.server_address"字段，如"localhost:50051"）
	grpcAddr := cfg.GetString("grpc.server_address")
	// 检查地址是否为空，为空则退出测试（服务端地址未配置，无法连接）
	if grpcAddr == "" {
		log.Fatalf("gRPC server address not configured")
	}

	// -------------------------- 第二步：创建gRPC客户端，建立与服务端的连接 --------------------------
	// 连接gRPC服务端：
	// - grpcAddr：服务端地址（如"localhost:50051"）
	// - grpc.WithTransportCredentials(insecure.NewCredentials())：使用"不安全"凭证（测试环境用，生产环境需用TLS加密）
	conn, err := grpc.Dial(grpcAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("Failed to connect: %v", err) // 连接失败退出测试（无法与服务端通信）
	}
	defer conn.Close() // 测试结束后自动关闭连接，避免资源泄漏

	// 创建会话服务的gRPC客户端stub（通过proto包生成，封装了所有会话相关接口的调用方法）
	client := proto.NewSessionServiceClient(conn)

	// 创建上下文：设置10秒超时（所有gRPC请求共享此上下文，超时后自动取消请求，避免无限等待）
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel() // 测试结束后自动取消上下文，释放资源

	// -------------------------- 第三步：测试1：创建游戏会话 --------------------------
	// 构造创建会话的请求：指定会话ID、最大玩家数（4人）、最小玩家数（2人）
	createResp, err := client.CreateSession(ctx, &proto.CreateSessionRequest{
		SessionId: "test-session-001", // 测试用会话ID（确保唯一性，避免与其他测试冲突）
		MaxPlayer: 4,                  // 会话最大容纳4人
		MinPlayer: 2,                  // 会话启动的最小玩家数（需至少2人）
	})

	// 处理创建会话的响应：先判断是否有调用错误（如网络问题、服务端未启动）
	if err != nil {
		log.Printf("CreateSession failed: %v", err)
		return // 创建会话失败，后续测试无法进行，退出程序
	}
	// 再判断服务端返回的"业务失败"（如会话ID已存在）
	if !createResp.Success {
		log.Printf("CreateSession failed: %s", createResp.Message)
		return // 业务失败，退出测试
	}

	// 提取创建成功的会话ID，用于后续测试（添加玩家、启动会话等）
	sessionId := createResp.SessionId
	log.Printf("✅ Created session: %s", sessionId) // 打印成功日志，带✅标识便于区分

	// -------------------------- 第四步：注册会话清理逻辑（确保测试后不留残留） --------------------------
	// defer匿名函数：测试结束后（无论正常还是异常），自动调用EndSession关闭会话
	// 作用：避免测试产生"僵尸会话"（创建后未关闭，占用服务端资源）
	defer func() {
		// 构造结束会话的请求
		endResp, err1 := client.EndSession(ctx, &proto.EndSessionRequest{SessionId: sessionId})
		// 处理清理的错误情况
		if err1 != nil {
			log.Printf("⚠️ Session cleanup failed: %v", err1) // ⚠️标识警告，清理失败但不影响测试结果
		} else if endResp != nil && !endResp.Success {
			log.Printf("⚠️ Session cleanup failed: %s", endResp.Message)
		} else if endResp == nil {
			log.Printf("⚠️ Session cleanup failed: nil response")
		} else {
			log.Printf("✅ Cleaned up session: %s", sessionId) // 清理成功
		}
	}()

	// -------------------------- 第五步：测试2：向会话添加玩家 --------------------------
	var getResp *proto.GetSessionResponse // 用于存储GetSession的响应，后续多次复用

	// 5.1 添加第一个玩家（player-1）
	addPlayerResp, err := client.AddPlayer(ctx, &proto.AddPlayerRequest{
		SessionId: sessionId, // 目标会话ID（刚创建的test-session-001）
		PlayerId:  "player-1",// 测试用玩家ID
	})
	// 处理添加玩家的响应
	if err != nil {
		log.Printf("AddPlayer (player-1) failed: %v", err)
	} else if !addPlayerResp.Success {
		log.Printf("AddPlayer (player-1) failed: %s", addPlayerResp.Message)
	} else {
		log.Printf("✅ AddPlayer (player-1) success: %v", addPlayerResp)
	}

	// 5.2 添加第二个玩家（player-2）：满足最小玩家数（2人），触发会话"可启动"状态
	addPlayerResp2, err := client.AddPlayer(ctx, &proto.AddPlayerRequest{
		SessionId: sessionId,
		PlayerId:  "player-2",
	})
	if err != nil {
		log.Printf("AddPlayer (player-2) failed: %v", err)
	} else if !addPlayerResp2.Success {
		log.Printf("AddPlayer (player-2) failed: %s", addPlayerResp2.Message)
	} else {
		log.Printf("✅ AddPlayer (player-2) success: %v", addPlayerResp2)
	}

	// 5.3 验证玩家数量：调用GetSession查看当前会话的玩家数是否达标（≥2人）
	getResp, err = client.GetSession(ctx, &proto.GetSessionRequest{SessionId: sessionId})
	if err != nil {
		log.Printf("GetSession (after add players) failed: %v", err)
	} else {
		log.Printf("Player count after additions: %d", getResp.PlayerCount)
		// 判断玩家数是否满足最小要求
		if getResp.PlayerCount < 2 {
			log.Printf("❌ Not enough players (need 2, got %d)", getResp.PlayerCount) // ❌标识测试不通过
		} else {
			log.Printf("✅ Minimum players requirement met (count: %d)", getResp.PlayerCount)
		}
	}

	// -------------------------- 第六步：测试3：获取会话详细信息 --------------------------
	getResp, err = client.GetSession(ctx, &proto.GetSessionRequest{
		SessionId: sessionId,
	})
	if err != nil {
		log.Printf("GetSession failed: %v", err)
	} else {
		// 打印会话详情：状态、玩家列表、玩家数量
		log.Printf("✅ GetSession success: State=%s, Players=%v, Count=%d", 
			getResp.State, getResp.Players, getResp.PlayerCount)
	}

	// -------------------------- 第七步：测试4：启动会话 --------------------------
	startResp, err := client.StartSession(ctx, &proto.StartSessionRequest{
		SessionId: sessionId,
	})
	// 处理启动会话的响应
	if err != nil {
		log.Printf("StartSession failed: %v", err)
	} else if !startResp.Success {
		log.Printf("StartSession failed: %s", startResp.Message)
	} else {
		log.Printf("✅ StartSession success: %v", startResp)

		// 7.1 验证会话状态：启动后应变为"StateRunning"（需与服务端状态枚举字符串一致）
		getResp, err1 := client.GetSession(ctx, &proto.GetSessionRequest{SessionId: sessionId})
		if err1 != nil {
			log.Printf("GetSession (after start) failed: %v", err1)
		} else {
			log.Printf("Session state after start: %s", getResp.State)
			// 检查状态是否符合预期（服务端SessionState的String()方法返回值需为"StateRunning"）
			if getResp.State != "StateRunning" {
				log.Printf("❌ Expected state 'StateRunning', got '%s'", getResp.State)
			} else {
				log.Printf("✅ Session state verified (running)")
			}
		}
	}

	// -------------------------- 第八步：测试5：结束会话 --------------------------
	endResp, err := client.EndSession(ctx, &proto.EndSessionRequest{
		SessionId: sessionId,
	})
	if err != nil {
		log.Printf("EndSession failed: %v", err)
	} else if !endResp.Success {
		log.Printf("EndSession failed: %s", endResp.Message)
	} else {
		log.Printf("✅ EndSession success: %v", endResp)
	}

	// -------------------------- 测试结束 --------------------------
	log.Println("gRPC client test completed.")
}